#include "Parent.h"
#include <assert.h>

Parent::Parent(){
	this->parentIndex = vector<pair<int, int>>();
	this->parentChainIndex = map<int, vector<int>>();
}

int Parent::addParent(int stmtNum1, int stmtNum2){
	if(stmtNum1 <= 0 || stmtNum2 <= 0){
		return -1;
	}
	this->parentIndex.push_back(make_pair(stmtNum1, stmtNum2));
	map<int, vector<int>>::iterator it;
	if ((it = parentChainIndex.find(stmtNum1)) != parentChainIndex.end()){
		it->second.push_back(stmtNum2);
	}else{
		this->parentChainIndex[stmtNum1] = vector<int>(1, stmtNum2);
	}
	return parentIndex.size()-1;
}

vector<pair<int, int>> Parent::getParent(int stmtNum1, int stmtNum2){
	set<pair<int, int>>* matchingPairs = new set<pair<int, int>>();
	for(vector<pair<int, int>>::iterator it = parentIndex.begin(); it != parentIndex.end(); it++) {
		if((it->first == stmtNum1 || stmtNum1 == ANYVALUE) && 
			(it->second == stmtNum2 || stmtNum2 == ANYVALUE)){
				matchingPairs->insert(*it);
		}
	}
	return vector<pair<int, int>>(matchingPairs->begin(), matchingPairs->end());
}

vector<pair<int, int>> Parent::getParentStar(int stmtNum1, int stmtNum2){
	set<pair<int, int>>* result = new set<pair<int, int>>();
	map<int, vector<int>>::iterator it;
	if(stmtNum1 != ANYVALUE && stmtNum2 != ANYVALUE){
		if (stmtNum2 > stmtNum1 && parentChainIndex.find(stmtNum1) != parentChainIndex.end()){
			int child = stmtNum2;
			while(true){
				vector<pair<int, int>> matchingPair = getParent(ANYVALUE, child);
				if (matchingPair.size() == 1){ /* the most only 1 pair is found */
					child = matchingPair.front().first;
					if (child == stmtNum1){
						result->insert(make_pair(stmtNum1, stmtNum2));
						break;
					}
				}else{
					break;
				}
			}
		}
	}else if(stmtNum1 == ANYVALUE && stmtNum2 == ANYVALUE){
		buildMeshPairs(*result);
	}else if(stmtNum1 != ANYVALUE){
		if ((it = parentChainIndex.find(stmtNum1))!= parentChainIndex.end()){
			buildPairsFrom(*result, stmtNum1, it);
		}
	}else if(stmtNum2 != ANYVALUE){
		if ((it = parentChainIndex.find(stmtNum2))!= parentChainIndex.end()){
			buildPairsTo(*result, stmtNum2, it);
		}else{
			vector<pair<int, int>> matchingPair = getParent(ANYVALUE, stmtNum2);
			if (matchingPair.size() == 1){ /* the most only 1 pair is found */
				int parent = matchingPair.front().first;
				it = parentChainIndex.find(parent);
				buildPairsTo(*result, stmtNum2, it);
			}
		}
	}
	return vector<pair<int, int>>(result->begin(), result->end());
}

void Parent::buildPairsFrom(set<pair<int, int>> &result, int from, map<int, vector<int>>::iterator it){
	for (vector<int>::iterator itV = it->second.begin(); itV != it->second.end(); itV++){
		result.insert(make_pair(from, *itV));
		if (parentChainIndex.find(*itV) != parentChainIndex.end()){
			map<int, vector<int>>::iterator itK = parentChainIndex.find(*itV);
			buildPairsFrom(result, from, itK);
		}
	}
}

void Parent::buildPairsTo(set<pair<int, int>> &result, int to, map<int, vector<int>>::iterator it){
	int child = to;
	if (it->first != to){
		result.insert(make_pair(it->first, to));
		child = it->first;
	}
	if(it == parentChainIndex.begin()){
		return;
	}
	while(it != parentChainIndex.begin()){//loop back as long != parentChainIndex.begin()
		--it;
		for(vector<int>::iterator itX = it->second.begin(); itX != it->second.end(); itX++){
			if(*itX == child){
				result.insert(make_pair(it->first, to));
				child = it->first;
				break;
			}
		}
	}
}

void Parent::buildMeshPairs(set<pair<int, int>> &result){
	for(map<int, vector<int>>::iterator it = parentChainIndex.begin(); it != parentChainIndex.end(); it++){
		buildPairsFrom(result, it->first, it);
	}
}